// ------------------------------------------------------------------------------------------------
// File   : DX9PostFog.cpp
// Date   : 2011-01-26
// Author : Weng xiao yi
// Descr. : Create an Post process Fog Effect of the frame buffer and cover the back buffer
//
// ------------------------------------------------------------------------------------------------

// ------------------------------------------------------------------------------------------------
// HEADERS
// ------------------------------------------------------------------------------------------------
#include <engine_stdafx.h>
// ------------------------------------------------------------------------------------------------
// IMPLEMENTATION
// ------------------------------------------------------------------------------------------------
DX9AE_PostFog::DX9AE_PostFog()
: DX9AfterEffect()
{
	SetAllResourceNull();
}

DX9AE_PostFog::~DX9AE_PostFog()
{
	Shutdown();
}

void DX9AE_PostFog::SetAllResourceNull()
{
	m_afFactor[eDX9_AE_PostFog_Param_FOGTYPE] = -1;
	m_afFactor[eDX9_AE_PostFog_Param_NEARLOWDISTANCE] = 0.0f;
	m_afFactor[eDX9_AE_PostFog_Param_FARHIGHDISTANCE] = 0.0f;
	m_afFactor[eDX9_AE_PostFog_Param_NEARLOWDENSITY] = 0.5f;
	m_afFactor[eDX9_AE_PostFog_Param_FARHIGHDENSITY] = 0.5f;
}

void DX9AE_PostFog::ReInit()
{
	SetAllResourceNull();
}

void DX9AE_PostFog::OnDeviceLost()
{
	Shutdown();

	DX9AfterEffect::OnDeviceLost();
}

void DX9AE_PostFog::OnDeviceReset()
{
	DX9AfterEffect::OnDeviceReset();

	ReInit();
}

void DX9AE_PostFog::Shutdown()
{

}

void DX9AE_PostFog::Apply()
{	
	HRESULT hr;

	IHRRenderer* RI = GetHREngine()->GetRenderer();
	LPDIRECT3DDEVICE9 pD3DDev = (LPDIRECT3DDEVICE9)(RI->GetRealDevice());
	ICubeMaterial::MaterialList &Mat_list = ICubeMaterial::GetInstance().GetMaterialList();
	const ICubeMaterial::MaterialInfo &FogMaterial_info = Mat_list[ICubeMaterial::eMaterial_posteffect];

	GetSceneEffect()->StretchBackBufferToDecolor();


	GetCubeMaterialRenderer()->PushMaterial( FogMaterial_info.m_material, MM_Add );
	GetCubeMaterialRenderer()->ComputeMaterialPass();
	GetCubeMaterialRenderer()->OnePassPreRenderMaterial( 0 );

	// get vertex shader for this material
	DX9VertexShaderManager::DX9VSFeatureAfterEffect oVSFeature;
	oVSFeature.stKey.ulShaderVer	 = 20;

	switch( int(m_afFactor[eDX9_AE_PostFog_Param_FOGTYPE]) )
	{
	case 0:
		oVSFeature.stKey.ulEffectId      = AE_TYPE_FOG_LINEAR;
		oVSFeature.stKey.ulEffectSubType = 0;
		break;
	case 1:
		oVSFeature.stKey.ulEffectId      = AE_TYPE_FOG_LAYERED;
		oVSFeature.stKey.ulEffectSubType = 0;
		break;
	case 2:
		oVSFeature.stKey.ulEffectId      = AE_TYPE_FOG_LINEAR;
		oVSFeature.stKey.ulEffectSubType = AE_TYPE_FOG_LINEAR_EXP;
		break;
	case 3:
		oVSFeature.stKey.ulEffectId      = AE_TYPE_FOG_LINEAR;
		oVSFeature.stKey.ulEffectSubType = AE_TYPE_FOG_LINEAR_EXP2;
		break;
	default:
		oVSFeature.stKey.ulEffectId      = AE_TYPE_FOG_LINEAR;
		oVSFeature.stKey.ulEffectSubType = 0;
		break;
	}

	DX9VertexShader* pVertexShader = DX9GetVertexShaderManager()->GetShader(&oVSFeature);

	// get pixel shader for this material
	DX9PixelShaderManager::DX9PSFeatureAfterEffect oPSFeature;
	oPSFeature.stKey.ulShaderVer	  = 20;
	switch( int(m_afFactor[eDX9_AE_PostFog_Param_FOGTYPE]) )
	{
	case 0:
		oPSFeature.stKey.ulEffectId      = AE_TYPE_FOG_LINEAR;
		oPSFeature.stKey.ulEffectSubType = 0;
		break;
	case 1:
		oPSFeature.stKey.ulEffectId      = AE_TYPE_FOG_LAYERED;
		oPSFeature.stKey.ulEffectSubType = 0;
		break;
	case 2:
		oPSFeature.stKey.ulEffectId      = AE_TYPE_FOG_LINEAR;
		oPSFeature.stKey.ulEffectSubType = AE_TYPE_FOG_LINEAR_EXP;
		break;
	case 3:
		oPSFeature.stKey.ulEffectId      = AE_TYPE_FOG_LINEAR;
		oPSFeature.stKey.ulEffectSubType = AE_TYPE_FOG_LINEAR_EXP2;
		break;
	default:
		oPSFeature.stKey.ulEffectId      = AE_TYPE_FOG_LINEAR;
		oPSFeature.stKey.ulEffectSubType = 0;
		break;
	}
	DX9PixelShader* pPixelShader = DX9GetPixelShaderManager()->GetShader(&oPSFeature);

	// use shaders
	hr = pD3DDev->SetVertexShader(pVertexShader->GetShaderInterface());
	DX9Verify( SUCCEEDED(hr) );
	hr = pD3DDev->SetPixelShader(pPixelShader->GetShaderInterface());
	DX9Verify( SUCCEEDED(hr) );


	pD3DDev->SetTexture( 0, GetSceneEffect()->GetDecolorTexture() );
	pD3DDev->SetTexture( 1, GetSceneEffect()->GetBKDepthTexture() );

	VECTOR4FLOAT vScreenResolution;
	vScreenResolution.x = GetHR3DConfig()->GetScreenWidth();
	vScreenResolution.y = GetHR3DConfig()->GetScreenHeight();
	vScreenResolution.z = 0.5f / GetHR3DConfig()->GetScreenWidth();
	vScreenResolution.w = 0.5f / GetHR3DConfig()->GetScreenHeight();

	// upload constants
	if (pVertexShader->IsGlobalConstPresent( VS_GLOBAL_CONSTANT_SCREEN_RESOLUTION))
		pVertexShader->SetGlobalVector( VS_GLOBAL_CONSTANT_SCREEN_RESOLUTION, &vScreenResolution );
	
	D3DXMATRIX InvWVPMat = GetHR3DConfig()->GetCamera()->GetViewXProj();
	D3DXMatrixInverse( &InvWVPMat, NULL, &InvWVPMat );
	if (pPixelShader->IsGlobalConstPresent( PS_GLOBAL_CONSTANT_FOG_INVWVPMATRIX))
		pPixelShader->SetGlobalMatrix( PS_GLOBAL_CONSTANT_FOG_INVWVPMATRIX, &InvWVPMat );
	
	VECTOR4FLOAT vCameraPos = {0, 0, 0, 0};
	vCameraPos.x = GetHR3DConfig()->GetCamera()->GetEyePt().x;
	vCameraPos.y = GetHR3DConfig()->GetCamera()->GetEyePt().y;
	vCameraPos.z = GetHR3DConfig()->GetCamera()->GetEyePt().z;
	if (pPixelShader->IsGlobalConstPresent( PS_GLOBAL_CONSTANT_FOG_CAMERAPOS))
		pPixelShader->SetGlobalVector( PS_GLOBAL_CONSTANT_FOG_CAMERAPOS, &vCameraPos );

	VECTOR4FLOAT vFogLayer = 
	{
		m_afFactor[eDX9_AE_PostFog_Param_NEARLOWDISTANCE], 
		m_afFactor[eDX9_AE_PostFog_Param_FARHIGHDISTANCE],
		m_afFactor[eDX9_AE_PostFog_Param_NEARLOWDENSITY],
		m_afFactor[eDX9_AE_PostFog_Param_FARHIGHDENSITY]
	};
	if (pPixelShader->IsGlobalConstPresent( PS_GLOBAL_CONSTANT_FOG_LAYERMINMAX))
		pPixelShader->SetGlobalVector( PS_GLOBAL_CONSTANT_FOG_LAYERMINMAX, &vFogLayer );

	DWORD FogColor = GetWorld().GetPostProcessData()->PostFogColor;
	VECTOR4FLOAT vFogColor = { ((FogColor&0x00ff0000)>>16)/255.0f, ((FogColor&0x0000ff00)>>8)/255.0f, (FogColor&0x000000FF)/255.0f, 1.0f};
	if (pPixelShader->IsGlobalConstPresent( PS_GLOBAL_CONSTANT_FOG_COLOR))
		pPixelShader->SetGlobalVector( PS_GLOBAL_CONSTANT_FOG_COLOR, &vFogColor );

	DWORD FogColorTop = GetWorld().GetPostProcessData()->PostFogColorTop;
	VECTOR4FLOAT vFogColorTop = { ((FogColorTop&0x00ff0000)>>16)/255.0f, ((FogColorTop&0x0000ff00)>>8)/255.0f, (FogColorTop&0x000000FF)/255.0f, 1.0f};
	if (pPixelShader->IsGlobalConstPresent( PS_GLOBAL_CONSTANT_FOG_COLORTOP))
		pPixelShader->SetGlobalVector( PS_GLOBAL_CONSTANT_FOG_COLORTOP, &vFogColorTop );
	
	DWORD FogColorBottom = GetWorld().GetPostProcessData()->PostFogColorBottom;
	VECTOR4FLOAT vFogColorBottom = { ((FogColorBottom&0x00ff0000)>>16)/255.0f, ((FogColorBottom&0x0000ff00)>>8)/255.0f, (FogColorBottom&0x000000FF)/255.0f, 1.0f};
	if (pPixelShader->IsGlobalConstPresent( PS_GLOBAL_CONSTANT_FOG_COLORBOTTOM))
		pPixelShader->SetGlobalVector( PS_GLOBAL_CONSTANT_FOG_COLORBOTTOM, &vFogColorBottom );


	RI->DrawPrimitive( D3DPT_TRIANGLESTRIP, 0, 2 );


	pD3DDev->SetVertexShader(NULL);
	pD3DDev->SetPixelShader(NULL);
	pD3DDev->SetTexture( 0, NULL );
	pD3DDev->SetTexture( 1, NULL );

	GetCubeMaterialRenderer()->OnePassPostRenderMaterial( 0 );
	GetCubeMaterialRenderer()->PopMaterial();

}
